/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
 
package com.cburch.logisim.comp;

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;

import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.circuit.WireSet;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.instance.InstancePainter;
import com.cburch.logisim.proj.LogisimPreferences;
import com.cburch.logisim.UItools.GraphicsUtil;

public class ComponentDrawContext {
    private static final int PIN_OFFS = 2;
    private static final int PIN_RAD = 4;

    private java.awt.Component dest;
    private Circuit circuit;
    private CircuitState circuitState;
    private Graphics base;
    private Graphics g;
    private boolean printView;
    private WireSet highlightedWires;
    private InstancePainter instancePainter;

    public ComponentDrawContext(java.awt.Component dest,
            Circuit circuit, CircuitState circuitState,
            Graphics base, Graphics g, boolean printView) {
        this.dest = dest;
        this.circuit = circuit;
        this.circuitState = circuitState;
        this.base = base;
        this.g = g;
        this.printView = printView;
        this.highlightedWires = WireSet.EMPTY;
        this.instancePainter = new InstancePainter(this, null);
    }

    public ComponentDrawContext(java.awt.Component dest,
            Circuit circuit, CircuitState circuitState,
            Graphics base, Graphics g) {
        this(dest, circuit, circuitState, base, g, false);
    }
    
    public InstancePainter getInstancePainter() {
        return instancePainter;
    }
    
    public void setHighlightedWires(WireSet value) {
        this.highlightedWires = value == null ? WireSet.EMPTY : value;
    }
    
    public WireSet getHighlightedWires() {
        return highlightedWires;
    }

    public boolean getShowState() {
        return !printView;
    }

    public boolean isPrintView() {
        return printView;
    }

    public boolean shouldDrawColor() {
        return !printView;
    }

    public java.awt.Component getDestination() {
        return dest;
    }

    public Graphics getGraphics() {
        return g;
    }

    public Circuit getCircuit() {
        return circuit;
    }

    public CircuitState getCircuitState() {
        return circuitState;
    }

    public void setGraphics(Graphics g) {
        this.g = g;
    }

    public Object getGateShape() {
        return LogisimPreferences.getGateShape();
    }

    //
    // helper methods
    //
    public void drawBounds(Component comp) {
        GraphicsUtil.switchToWidth(g, 2);
        g.setColor(Color.BLACK);
        Bounds bds = comp.getBounds();
        g.drawRect(bds.getX(), bds.getY(),
                bds.getWidth(), bds.getHeight());
        GraphicsUtil.switchToWidth(g, 1);
    }

    public void drawRectangle(Component comp) {
        drawRectangle(comp, "");
    }
    
    public void drawRectangle(Component comp, String label) {
        Bounds bds = comp.getBounds(g);
        drawRectangle(bds.getX(), bds.getY(), bds.getWidth(),
            bds.getHeight(), label);
    }

    public void drawRectangle(int x, int y,
            int width, int height, String label) {
        GraphicsUtil.switchToWidth(g, 2);
        g.drawRect(x, y, width, height);
        if(label != null && !label.equals("")) {
            FontMetrics fm = base.getFontMetrics(g.getFont());
            int lwid = fm.stringWidth(label);
            if(height > 20) { // centered at top edge
                g.drawString(label, x + (width - lwid) / 2,
                    y + 2 + fm.getAscent());
            } else { // centered overall
                g.drawString(label, x + (width - lwid) / 2,
                    y + (height + fm.getAscent()) / 2 - 1);
            }
        }
    }
    
    public void drawRectangle(ComponentFactory source, int x, int y,
            AttributeSet attrs, String label) {
        Bounds bds = source.getOffsetBounds(attrs);
        drawRectangle(source, x + bds.getX(), y + bds.getY(), bds.getWidth(),
            bds.getHeight(), label);
    }

    public void drawRectangle(ComponentFactory source, int x, int y,
            int width, int height, String label) {
        GraphicsUtil.switchToWidth(g, 2);
        g.drawRect(x + 1, y + 1, width - 1, height - 1);
        if(label != null && !label.equals("")) {
            FontMetrics fm = base.getFontMetrics(g.getFont());
            int lwid = fm.stringWidth(label);
            if(height > 20) { // centered at top edge
                g.drawString(label, x + (width - lwid) / 2,
                    y + 2 + fm.getAscent());
            } else { // centered overall
                g.drawString(label, x + (width - lwid) / 2,
                    y + (height + fm.getAscent()) / 2 - 1);
            }
        }
    }

    public void drawDongle(int x, int y) {
        GraphicsUtil.switchToWidth(g, 2);
        g.drawOval(x - 4, y - 4, 9, 9);
    }

    public void drawPin(Component comp, int i,
            String label, Direction dir) {
        Color curColor = g.getColor();
        if(i < 0 || i >= comp.getEnds().size()) return;
        EndData e = (EndData) comp.getEnd(i);
        Location pt = e.getLocation();
        int x = pt.getX();
        int y = pt.getY();
        if(getShowState()) {
            CircuitState state = getCircuitState();
            g.setColor(state.getValue(pt).getColor());
        } else {
            g.setColor(Color.BLACK);
        }
        g.fillOval(x - PIN_OFFS, y - PIN_OFFS, PIN_RAD, PIN_RAD);
        g.setColor(curColor);
        if(dir == Direction.EAST) {
            GraphicsUtil.drawText(g, label, x + 3, y,
                    GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER);
        } else if(dir == Direction.WEST) {
            GraphicsUtil.drawText(g, label, x - 3, y,
                    GraphicsUtil.H_RIGHT, GraphicsUtil.V_CENTER);
        } else if(dir == Direction.SOUTH) {
            GraphicsUtil.drawText(g, label, x, y - 3,
                    GraphicsUtil.H_CENTER, GraphicsUtil.V_BASELINE);
        } else if(dir == Direction.NORTH) {
            GraphicsUtil.drawText(g, label, x, y + 3,
                    GraphicsUtil.H_CENTER, GraphicsUtil.V_TOP);
        }
    }

    public void drawPin(Component comp, int i) {
        EndData e = (EndData) comp.getEnd(i);
        Location pt = e.getLocation();
        Color curColor = g.getColor();
        if(getShowState()) {
            CircuitState state = getCircuitState();
            g.setColor(state.getValue(pt).getColor());
        } else {
            g.setColor(Color.BLACK);
        }
        g.fillOval(pt.getX() - PIN_OFFS, pt.getY() - PIN_OFFS, PIN_RAD, PIN_RAD);
        g.setColor(curColor);
    }

    public void drawPins(Component comp) {
        Color curColor = g.getColor();
        java.util.Iterator it = comp.getEnds().iterator();
        while(it.hasNext()) {
            EndData e = (EndData) it.next();
            Location pt = e.getLocation();
            if(getShowState()) {
                CircuitState state = getCircuitState();
                g.setColor(state.getValue(pt).getColor());
            } else {
                g.setColor(Color.BLACK);
            }
            g.fillOval(pt.getX() - PIN_OFFS, pt.getY() - PIN_OFFS, PIN_RAD, PIN_RAD);
        }
        g.setColor(curColor);
    }

    public void drawClock(Component comp, int i,
            Direction dir) {
        Color curColor = g.getColor();
        g.setColor(Color.BLACK);
        GraphicsUtil.switchToWidth(g, 2);

        EndData e = (EndData) comp.getEnd(i);
        Location pt = e.getLocation();
        int x = pt.getX();
        int y = pt.getY();
        final int CLK_SZ = 4;
        final int CLK_SZD = CLK_SZ - 1;
        if(dir == Direction.NORTH) {
            g.drawLine(x - CLK_SZD, y - 1, x, y - CLK_SZ);
            g.drawLine(x + CLK_SZD, y - 1, x, y - CLK_SZ);
        } else if(dir == Direction.SOUTH) {
            g.drawLine(x - CLK_SZD, y + 1, x, y + CLK_SZ);
            g.drawLine(x + CLK_SZD, y + 1, x, y + CLK_SZ);
        } else if(dir == Direction.EAST) {
            g.drawLine(x + 1, y - CLK_SZD, x + CLK_SZ, y);
            g.drawLine(x + 1, y + CLK_SZD, x + CLK_SZ, y);
        } else if(dir == Direction.WEST) {
            g.drawLine(x - 1, y - CLK_SZD, x - CLK_SZ, y);
            g.drawLine(x - 1, y + CLK_SZD, x - CLK_SZ, y);
        }

        g.setColor(curColor);
        GraphicsUtil.switchToWidth(g, 1);
    }

    public void drawHandles(Component comp) {
        Bounds b = comp.getBounds(g);
        int left = b.getX();
        int right = left + b.getWidth();
        int top = b.getY();
        int bot = top + b.getHeight();
        drawHandle(right, top);
        drawHandle(left,  bot);
        drawHandle(right, bot);
        drawHandle(left,  top);
    }
    
    public void drawHandle(Location loc) {
        drawHandle(loc.getX(), loc.getY());
    }

    public void drawHandle(int x, int y) {
        g.setColor(Color.white);
        g.fillRect(x - 3, y - 3, 7, 7);
        g.setColor(Color.black);
        g.drawRect(x - 3, y - 3, 7, 7);
    }

}
